package org.sacgtug.android;

import java.util.HashMap;
import java.util.Map;

import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class LocationActivity extends Activity implements LocationListener, SensorEventListener {

	// Reference local HTML file, which is located in the assets folder
	private static final String MAP_URL = "file:///android_asset/location.html";
	private WebView webView;
	private Location mostRecentLocation;

	private static final String LOG_PREFIX = "LOC";
	
	// Location
	private static final String LONG = "LONG";
	private static final String LATI = "LATI";

	// Sensor
	private static final String AZIMUTH = "AZIMUTH";
	private static final String PITCH = "PITCH";
	private static final String ROLL = "ROLL";
	private static final int AZIMUTH_INDEX = 0;
	private static final int PITCH_INDEX = 1;
	private static final int ROLL_INDEX = 2;
	private int sensorEventCounter = 0;
	private static final int SENSOR_EVENT_SKIP_RATE = 10;
	
	private Handler mHandler = new Handler();

	private JsonDbAdapter mJsonDbAdapter;

	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		// DB
		mJsonDbAdapter = new JsonDbAdapter(this);
		mJsonDbAdapter.open();

		// Setup WebView, location and sensor services
		setupWebView();
		setupLocation();
		setupSensor();

		this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
	}

	private void setupWebView() {

		webView = (WebView) findViewById(R.id.webview);
		webView.getSettings().setJavaScriptEnabled(true);

		webView.setWebViewClient(new WebViewClient() {
			@Override
			public void onPageFinished(WebView view, String url) {
				Log.i(LOG_PREFIX, "onPageFinished : url = " + url);
				sendLocation(getLocationJSON(mostRecentLocation));
			}
		});

		webView.loadUrl(MAP_URL);
	}

	private void setupLocation() {

		LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		Criteria criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		String provider = locationManager.getBestProvider(criteria, true);

		locationManager.requestLocationUpdates(provider, 1, 0, this);

		mostRecentLocation = locationManager.getLastKnownLocation(provider);
	}

	private void setupSensor() {

		SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
		sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.  TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
	}


	public void onLocationChanged(Location location) {

		Log.i(LOG_PREFIX, "onLocationChanged");

		mostRecentLocation = location;

		sendLocation(getLocationJSON(location));
	}

	/*
	 * The following methods are only necessary because LocationActivity implements LocationListener
	 */

	public void onProviderDisabled(String provider) {
		Log.i(LOG_PREFIX, "onProviderDisabled");
	}

	public void onProviderEnabled(String provider) { 
		Log.i(LOG_PREFIX, "onProviderEnabled");
	}

	public void onStatusChanged(String provider, int status, Bundle extras) { 
		Log.i(LOG_PREFIX, "onStatusChanged");
	}

	private void sendLocation(final String json) {

		// Persist location
		mJsonDbAdapter.put(json);

		mHandler.post(new Runnable() {
			
			public void run() {
			
				Log.i(LOG_PREFIX, "sendLocation : json = " + json);
				
				// Calling JavaScript method defined in assets/location.js
				webView.loadUrl("javascript:showLocation(" + json + ")");
				
				showOldGpsData();
			}
		});
	}

	private String getLocationJSON(Location location) {

		if (null == location) {
			return "{\"" + LATI + "\":-, \"" + LONG + "\":-}";
		}

		Map<String, String> locationData = new HashMap<String, String>();
		locationData.put(LONG, String.valueOf(location.getLongitude()));
		locationData.put(LATI, String.valueOf(location.getLatitude()));

		return new JSONObject(locationData).toString();
	}

	public void onAccuracyChanged(Sensor arg0, int arg1) {
		//Log.i(LOG_PREFIX, "onAccuracyChanged");
	}

	public void onSensorChanged(SensorEvent event) {

//		Log.i(LOG_PREFIX, "AZIMUHT: " + event.values[AZIMUTH_INDEX]);
//		Log.i(LOG_PREFIX, "PITCH: " + event.values[PITCH_INDEX]);
//		Log.i(LOG_PREFIX, "ROLL: " + event.values[ROLL_INDEX]);

		if(0 == sensorEventCounter) {
			
			Map<String, String> sensorData = new HashMap<String, String>();
			sensorData.put(AZIMUTH, String.valueOf(event.values[AZIMUTH_INDEX]));
			sensorData.put(PITCH, String.valueOf(event.values[PITCH_INDEX]));
			sensorData.put(ROLL, String.valueOf(event.values[ROLL_INDEX]));
			webView.loadUrl("javascript:showSensorData(" + new JSONObject(sensorData).toString() + ")");
			sensorEventCounter++;
		}
		else if(SENSOR_EVENT_SKIP_RATE == sensorEventCounter) {
			
			sensorEventCounter = 0;
		}
		else {
			sensorEventCounter++;
		}
	}

	private void showOldGpsData() {

		// List existing stored locations
		Cursor dataCursor = mJsonDbAdapter.get();
		startManagingCursor(dataCursor);
		dataCursor.moveToFirst();
		int idField = dataCursor.getColumnIndex(JsonDbAdapter.FIELD_ID);
		int jsonField = dataCursor.getColumnIndex(JsonDbAdapter.FIELD_JSON);

		for(;dataCursor.isAfterLast() == false; dataCursor.moveToNext()) {

			Log.i(LOG_PREFIX, "id = " + dataCursor.getInt(idField));
			Log.i(LOG_PREFIX, "json = " + dataCursor.getString(jsonField));

			webView.loadUrl("javascript:showOldLocation(" + dataCursor.getString(jsonField) + ")");	
		}
	}
}